<?php

if (!defined('LOG_WARNING')) {
	define('LOG_WARNING', 3);
}
if (!defined('LOG_NOTICE')) {
	define('LOG_NOTICE', 4);
}
if (!defined('LOG_DEBUG')) {
	define('LOG_DEBUG', 5);
}
if (!defined('LOG_INFO')) {
	define('LOG_INFO', 6);
}
if (!defined('LOGS')) {
	define('LOGS', TMP . DS . 'logs' . DS);
}

class PspLog {
	public static $_streams = array();

/**

 * {{{
 * PspLog::config('second_file', array(
 * 		'engine' => 'FileLog',
 * 		'path' => '/var/logs/my_app/'
 * ));
 * }}}

 */
	public static function config($key, $config) {
		if (empty($config['engine'])) {
			trigger_error('Missing logger classname', E_USER_WARNING);
			return false;
		}
		$className = self::_getLogger($config['engine']);
		if (!$className) {
			return false;
		}
		unset($config['engine']);
		self::$_streams[$key] = new $className($config);
		return true;
	}

	public static function _getLogger($loggerName) {
		Loader::import('pspframework.log.'.$loggerName);
		if (!class_exists($loggerName)) {
			trigger_error(sprintf('Could not load logger class %s', $loggerName), E_USER_WARNING);
			return false;
		}
		if (!is_callable(array($loggerName, 'write'))) {
			trigger_error(
				sprintf('logger class %s does not implement a write method.', $loggerName),
				E_USER_WARNING
			);
			return false;
		}
		return $loggerName;
	}


	public static function configured() {
		return array_keys(self::$_streams);
	}


	public static function drop($streamName) {
		unset(self::$_streams[$streamName]);
	}


	public static function _autoConfig() {
		if (!class_exists('FileLog')) {
			Loader::import('pspframework.log.FileLog');
		}
		self::$_streams['default'] =& new FileLog(array('path' => LOGS));
	}

/**

 * `PspLog::write('warning', 'Stuff is broken here');`

 */
	public static function write($type, $message) {
		if (!defined('LOG_ERROR')) {
			define('LOG_ERROR', 2);
		}
		if (!defined('LOG_ERR')) {
			define('LOG_ERR', LOG_ERROR);
		}
		$levels = array(
			LOG_WARNING => 'warning',
			LOG_NOTICE => 'notice',
			LOG_INFO => 'info',
			LOG_DEBUG => 'debug',
			LOG_ERR => 'error',
			LOG_ERROR => 'error'
		);
		if (is_int($type) && isset($levels[$type])) {
			$type = $levels[$type];
		}
		if (empty(self::$_streams)) {
			self::_autoConfig();
		}
		$keys = array_keys(self::$_streams);
		foreach ($keys as $key) {
			$logger =& self::$_streams[$key];
			$logger->write($type, $message);
		}
		return true;
	}

	public static function handleError($code, $description, $file = null, $line = null, $context = null) {
		if ($code === 2048 || $code === 8192) {
			return;
		}
		switch ($code) {
			case E_PARSE:
			case E_ERROR:
			case E_CORE_ERROR:
			case E_COMPILE_ERROR:
			case E_USER_ERROR:
				$error = 'Fatal Error';
				$level = LOG_ERROR;
			break;
			case E_WARNING:
			case E_USER_WARNING:
			case E_COMPILE_WARNING:
			case E_RECOVERABLE_ERROR:
				$error = 'Warning';
				$level = LOG_WARNING;
			break;
			case E_NOTICE:
			case E_USER_NOTICE:
				$error = 'Notice';
				$level = LOG_NOTICE;
			break;
			default:
				return;
			break;
		}
		$message = $error . ' (' . $code . '): ' . $description . ' in [' . $file . ', line ' . $line . ']';
		self::write($level, $message);
	}
}

if (!defined('DISABLE_DEFAULT_ERROR_HANDLING')) {
	set_error_handler(array('PspLog', 'handleError'));
}
